home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fs / fsSelect.c < prev    next >
C/C++ Source or Header  |  1991-08-08  |  25KB  |  809 lines

  1. /* 
  2.  * fsSelect.c --
  3.  *
  4.  *    Routines to implement the Fs_Select system call.
  5.  *
  6.  *    Features:
  7.  *    1) There is a limit on the number of streams that can be selected.
  8.  *       (This routine silently limits it to 1024.)
  9.  *    2) If the 3 bit masks are NULL, and the timeout value is not 0, 
  10.  *       then Sync_WaitTime is called to wait and FS_TIMEOUT is returned
  11.  *       with numReady = 0.
  12.  *    3) The file-type select routine must handle an empty inFlags value
  13.  *       by setting outFlags to 0.
  14.  *    4) If all bits are cleared in the bit masks, SUCCESS is returned
  15.  *       with numReady = 0.
  16.  
  17.  *
  18.  * Copyright 1986 Regents of the University of California
  19.  * All rights reserved.
  20.  */
  21.  
  22. #ifndef lint
  23. static char rcsid[] = "$Header: /sprite/src/kernel/fs/RCS/fsSelect.c,v 9.6 91/08/08 11:51:59 shirriff Exp $ SPRITE (Berkeley)";
  24. #endif not lint
  25.  
  26. #define MACH_UNIX_COMPAT
  27.  
  28. #include <sprite.h>
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #include <assert.h>
  32. #include <mach.h>
  33. #include <fs.h>
  34. #include <fsutil.h>
  35. #include <fsNameOps.h>
  36. #include <fsUnixStubs.h>
  37. #include <procUnixStubs.h>
  38. #include <fsio.h>
  39. #include <sync.h>
  40. #include <list.h>
  41. #include <proc.h>
  42. #include <sig.h>
  43. #include <dbg.h>
  44. #include <timer.h>
  45. #include <rpc.h>
  46. #include <vm.h>
  47.  
  48. static char *errs[] = {"ENOERR", "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO",
  49.         "ENXIO", "E2BIG", "ENOEXEC", "EBADF", "ECHILD", "EAGAIN", "ENOMEM",
  50.         "EACCES", "EFAULT", "ENOTBLK", "EBUSY", "EEXIST", "EXDEV", "ENODEV",
  51.         "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE", "ENOTTY",
  52.         "ETXTBSY", "EFBIG", "ENOSPC", "ESPIPE", "EROFS", "EMLINK", "EPIPE",
  53.         "EDOM", "ERANGE", "EWOULDBLOCK", "EINPROGRESS", "EALREADY", "ENOTSOCK",
  54.         "EDESTADDRREQ", "EMSGSIZE", "EPROTOTYPE", "ENOPROTOOPT",
  55.         "EPROTONOSUPPORT", "ESOCKTNOSUPPORT", "EOPNOTSUPP", "EPFNOSUPPORT",
  56.         "EAFNOSUPPORT", "EADDRINUSE", "EADDRNOTAVAIL", "ENETDOWN",
  57.         "ENETUNREACH", "ENETRESET", "ECONNABORTED", "ECONNRESET", "ENOBUFS",
  58.         "EISCONN", "ENOTCONN", "ESHUTDOWN", "ETIMEDOUT", "ECONNREFUSED",
  59.         "ELOOP", "ENAMETOOLONG", "EHOSTDOWN", "EHOSTUNREACH", "ENOTEMPTY",
  60.         "EPROCLIM", "EUSERS", "EDQUOT", "ESTALE", "EREMOTE"};
  61.  
  62. #undef Mach_SetErrno
  63. #define Mach_SetErrno(err) if (debugFsStubs) \
  64.         printf("Error %d (%s) at %d in %s\n", err,\
  65.         err<sizeof(errs)/sizeof(char *)?errs[err]:"",\
  66.         __LINE__, __FILE__); Proc_GetActualProc()->unixErrno = (err)
  67.  
  68. /*
  69.  * Internal limit on the number of streams that can be checked.
  70.  * This needs to be moved to an external header file!!
  71.  */
  72. #define MAX_NUM_STREAMS        1024
  73.  
  74. /*
  75.  * Number of bits within a row of the bitmask. Assumes a row
  76.  * is a 32-bit integer.
  77.  */
  78. #define BITS_PER_ROW    32
  79.  
  80. /*
  81.  * Maximum number of rows of bitmasks.
  82.  */
  83. #define MAX_NUM_ROWS    (MAX_NUM_STREAMS / BITS_PER_ROW)
  84.  
  85.  
  86. /*
  87.  * Structure passed to the timeout proc to allow the process to be woken up.
  88.  */
  89. typedef struct {
  90.     Proc_ControlBlock    *procPtr;
  91.     int            timeOut;
  92. } WakeupInfo;
  93.  
  94. /*
  95.  * Routine called in FsSelect if the call timed-out.
  96.  */
  97. static void TimeoutProc _ARGS_((Timer_Ticks ticks, ClientData clientData));
  98.  
  99. static ReturnStatus readInMasks _ARGS_ ((int numStreams, int *userReadMaskPtr,
  100.     int *readMaskPtr, int *userWriteMaskPtr, int *writeMaskPtr,
  101.     int *userExceptMaskPtr, int *exceptMaskPtr));
  102.  
  103. static ReturnStatus writeOutMasks _ARGS_ ((int numStreams,
  104.     int *userReadMaskPtr, int *readMaskPtr, int *userWriteMaskPtr, 
  105.     int *writeMaskPtr, int *userExceptMaskPtr, int *exceptMaskPtr));
  106.  
  107. /*
  108.  *----------------------------------------------------------------------
  109.  *
  110.  * Fs_SelectStub --
  111.  *
  112.  *      This is the stub for the Fs_Select system call. The bitmasks
  113.  *    are examined to see if the corresponding stream is readble, writable,
  114.  *    and/or has an exception condition pending. The user may give a
  115.  *    timeout period to limit the amount of time to wait.
  116.  *
  117.  * Results:
  118.  *    SUCCESS            - the operation was successful.
  119.  *    FS_TIMEOUT        - if a timeout period was specified, and no
  120.  *                    streams were ready within the time-out period.
  121.  *    SYS_ARG_NOACCESS    - an invalid address for an argument was
  122.  *                  given.
  123.  *    SYS_INVALID_ARG        - an invalid stream ID was given in one
  124.  *                  of the bitmaps.
  125.  *    GEN_ABORTED_BY_SIGNAL    - a signal came in.
  126.  *
  127.  * Side effects:
  128.  *    The process may be put to sleep.
  129.  *
  130.  *----------------------------------------------------------------------
  131.  */
  132. /*ARGSUSED*/
  133. ReturnStatus
  134. Fs_SelectStub(numStreams, userTimeoutPtr, userReadMaskPtr, userWriteMaskPtr, 
  135.     userExceptMaskPtr, numReadyPtr)
  136.     int        numStreams;    /* The length in bits of the read and write 
  137.                  * masks. */
  138.     Time    *userTimeoutPtr;/* Timer value indicating timeout period or
  139.                  * USER_NIL if no timeout. (in/out) */
  140.     int        *userReadMaskPtr;
  141.                 /* A bitmask indicating stream ID's to check
  142.                  * for readability. (in/out) */
  143.     int        *userWriteMaskPtr;
  144.                 /* A bitmask indicating stream ID's to check
  145.                  * for writability. (in/out) */
  146.     int        *userExceptMaskPtr;
  147.                 /* A bitmask indicating stream ID's to check
  148.                  * for exception conditions. (in/out) */
  149.     int        *numReadyPtr;    /* On return indicates the number of streams
  150.                  * ready for I/O. (out) */
  151.  
  152. {
  153.     Time        timeout;    /* Copy of *userTimeoutPtr. */
  154.     Time                *timeoutPtr;
  155.     int                 numReady = 0;
  156.     int                 doTimeout;
  157.     ReturnStatus        status, writeStatus;
  158.     int            inReadMasks[MAX_NUM_ROWS];
  159.     int            inWriteMasks[MAX_NUM_ROWS];
  160.     int            inExceptMasks[MAX_NUM_ROWS];
  161.     int            outReadMasks[MAX_NUM_ROWS];
  162.     int            outWriteMasks[MAX_NUM_ROWS];
  163.     int            outExceptMasks[MAX_NUM_ROWS];
  164.     int                 *inReadMaskPtr;
  165.     int                 *outReadMaskPtr;
  166.     int                 *inWriteMaskPtr;
  167.     int                 *outWriteMaskPtr;
  168.     int                 *inExceptMaskPtr;
  169.     int                 *outExceptMaskPtr;
  170.  
  171.     if ((userReadMaskPtr == (int *) USER_NIL) &&
  172.         (userWriteMaskPtr == (int *) USER_NIL) &&
  173.         (userExceptMaskPtr == (int *) USER_NIL)) {
  174.     numStreams = 0;
  175.     }
  176.  
  177.     /*
  178.      * Make sure the number of streams is in the proper range.
  179.      */
  180.     if (numStreams < 0) {
  181.     return(SYS_INVALID_ARG);
  182.     } else if (numStreams > MAX_NUM_STREAMS) {
  183.     numStreams = MAX_NUM_STREAMS;
  184.     }
  185.  
  186.     if (userTimeoutPtr == (Time *) USER_NIL) {
  187.     timeoutPtr = (Time *) NIL;
  188.     } else {
  189.     if (Vm_CopyIn(sizeof(Time), (Address) userTimeoutPtr, 
  190.                 (Address) &timeout) != SUCCESS) {
  191.         return(SYS_ARG_NOACCESS);
  192.     }
  193.     timeoutPtr = &timeout;
  194.     }
  195.     if (userReadMaskPtr == USER_NIL) {
  196.     inReadMaskPtr = (int *) NIL;
  197.     outReadMaskPtr = (int *) NIL;
  198.     } else {
  199.     inReadMaskPtr = inReadMasks;
  200.     outReadMaskPtr = outReadMasks;
  201.     }
  202.     if (userWriteMaskPtr == USER_NIL) {
  203.     inWriteMaskPtr = (int *) NIL;
  204.     outWriteMaskPtr = (int *) NIL;
  205.     } else {
  206.     inWriteMaskPtr = inWriteMasks;
  207.     outWriteMaskPtr = outWriteMasks;
  208.     }
  209.     if (userExceptMaskPtr == USER_NIL) {
  210.     inExceptMaskPtr = (int *) NIL;
  211.     outExceptMaskPtr = (int *) NIL;
  212.     } else {
  213.     inExceptMaskPtr = inExceptMasks;
  214.     outExceptMaskPtr = outExceptMasks;
  215.     }
  216.     status = readInMasks(numStreams, userReadMaskPtr, inReadMaskPtr,
  217.     userWriteMaskPtr, inWriteMaskPtr, userExceptMaskPtr, inExceptMaskPtr);
  218.     if (status != SUCCESS) {
  219.     return(SYS_ARG_NOACCESS);
  220.     }
  221.     status = Fs_Select(numStreams, timeoutPtr, inReadMaskPtr, outReadMaskPtr,
  222.     inWriteMaskPtr, outWriteMaskPtr, inExceptMaskPtr, outExceptMaskPtr,
  223.     &numReady, &doTimeout);
  224.     if (status == SUCCESS || status == FS_TIMEOUT) {
  225.     writeStatus = writeOutMasks(numStreams, userReadMaskPtr,
  226.         outReadMaskPtr, userWriteMaskPtr, outWriteMaskPtr,
  227.            userExceptMaskPtr, outExceptMaskPtr);
  228.     if (status == SUCCESS && doTimeout && writeStatus==SUCCESS) {
  229.         writeStatus = Vm_CopyOut(sizeof(timeout), (Address) &timeout, 
  230.                             (Address) userTimeoutPtr);
  231.     }
  232.     if (writeStatus != SUCCESS) {
  233.         status = SYS_ARG_NOACCESS;
  234.     }
  235.     }
  236.     if (Vm_CopyOut(sizeof(*numReadyPtr), (Address) &numReady, 
  237.                    (Address) numReadyPtr) != SUCCESS) {
  238.     status = SYS_ARG_NOACCESS;
  239.     }
  240.     return(status);
  241. }
  242.  
  243. /*
  244.  *----------------------------------------------------------------------
  245.  *
  246.  * Fs_NewSelectStub --
  247.  *
  248.  *      The stub for the "select" Unix system call.
  249.  *
  250.  * Results:
  251.  *      Returns -1 on failure.
  252.  *
  253.  * Side effects:
  254.  *      Side effects associated with the system call.
  255.  *
  256.  *
  257.  *----------------------------------------------------------------------
  258.  */
  259. int
  260. Fs_NewSelectStub(numStreams, userReadMaskPtr, userWriteMaskPtr,
  261.               userExceptMaskPtr, userTimeoutPtr)
  262.     int        numStreams;    /* The length in bits of the read and write 
  263.                  * masks. */
  264.     int        *userReadMaskPtr;
  265.                 /* A bitmask indicating stream ID's to check
  266.                  * for readability. (in/out) */
  267.     int        *userWriteMaskPtr;
  268.                 /* A bitmask indicating stream ID's to check
  269.                  * for writability. (in/out) */
  270.     int        *userExceptMaskPtr;
  271.                 /* A bitmask indicating stream ID's to check
  272.                  * for exception conditions. (in/out) */
  273.     Time    *userTimeoutPtr;/* Timer value indicating timeout period or
  274.                  * USER_NIL if no timeout. (in/out) */
  275.  
  276. {
  277.     Time        timeout;    /* Copy of *userTimeoutPtr. */
  278.     Time                *timeoutPtr;
  279.     int                 numReady = 0;
  280.     int                 doTimeout;
  281.     ReturnStatus        status, writeStatus;
  282.     int            inReadMasks[MAX_NUM_ROWS];
  283.     int            inWriteMasks[MAX_NUM_ROWS];
  284.     int            inExceptMasks[MAX_NUM_ROWS];
  285.     int            outReadMasks[MAX_NUM_ROWS];
  286.     int            outWriteMasks[MAX_NUM_ROWS];
  287.     int            outExceptMasks[MAX_NUM_ROWS];
  288.     int                 *inReadMaskPtr;
  289.     int                 *outReadMaskPtr;
  290.     int                 *inWriteMaskPtr;
  291.     int                 *outWriteMaskPtr;
  292.     int                 *inExceptMaskPtr;
  293.     int                 *outExceptMaskPtr;
  294.     extern int          debugFsStubs;
  295.  
  296.     if (debugFsStubs) {
  297.     printf("Fs_NewSelectStub(%d, %x, %x, %x, %x)\n", numStreams,
  298.         userReadMaskPtr, userWriteMaskPtr, userExceptMaskPtr,
  299.         userTimeoutPtr);
  300.     }
  301.  
  302.     if ((userReadMaskPtr == (int *) USER_NIL) &&
  303.         (userWriteMaskPtr == (int *) USER_NIL) &&
  304.         (userExceptMaskPtr == (int *) USER_NIL)) {
  305.     numStreams = 0;
  306.     }
  307.  
  308.     /*
  309.      * Make sure the number of streams is in the proper range.
  310.      */
  311.     if (numStreams < 0) {
  312.     Mach_SetErrno(EINVAL);
  313.     } else if (numStreams > MAX_NUM_STREAMS) {
  314.     numStreams = MAX_NUM_STREAMS;
  315.     }
  316.  
  317.     if (userTimeoutPtr == (Time *) USER_NIL) {
  318.     timeoutPtr = (Time *) NIL;
  319.     } else {
  320.     if (Vm_CopyIn(sizeof(Time), (Address) userTimeoutPtr, 
  321.                 (Address) &timeout) != SUCCESS) {
  322.         Mach_SetErrno(EFAULT);
  323.         return -1;
  324.     }
  325.     timeoutPtr = &timeout;
  326.     }
  327.     if (userReadMaskPtr == USER_NIL) {
  328.     inReadMaskPtr = (int *) NIL;
  329.     outReadMaskPtr = (int *) NIL;
  330.     } else {
  331.     inReadMaskPtr = inReadMasks;
  332.     outReadMaskPtr = outReadMasks;
  333.     }
  334.     if (userWriteMaskPtr == USER_NIL) {
  335.     inWriteMaskPtr = (int *) NIL;
  336.     outWriteMaskPtr = (int *) NIL;
  337.     } else {
  338.     inWriteMaskPtr = inWriteMasks;
  339.     outWriteMaskPtr = outWriteMasks;
  340.     }
  341.     if (userExceptMaskPtr == USER_NIL) {
  342.     inExceptMaskPtr = (int *) NIL;
  343.     outExceptMaskPtr = (int *) NIL;
  344.     } else {
  345.     inExceptMaskPtr = inExceptMasks;
  346.     outExceptMaskPtr = outExceptMasks;
  347.     }
  348.  
  349.     status = readInMasks(numStreams, userReadMaskPtr, inReadMaskPtr,
  350.     userWriteMaskPtr, inWriteMaskPtr, userExceptMaskPtr, inExceptMaskPtr);
  351.     if (status != SUCCESS) {
  352.     Mach_SetErrno(EFAULT);
  353.     return -1;
  354.     }
  355.     status = Fs_Select(numStreams, timeoutPtr, inReadMaskPtr, outReadMaskPtr,
  356.     inWriteMaskPtr, outWriteMaskPtr, inExceptMaskPtr, outExceptMaskPtr,
  357.     &numReady, &doTimeout);
  358.     if (status == SUCCESS || status == FS_TIMEOUT) {
  359.     writeStatus = writeOutMasks(numStreams, userReadMaskPtr,
  360.         outReadMaskPtr, userWriteMaskPtr, outWriteMaskPtr,
  361.             userExceptMaskPtr, outExceptMaskPtr);
  362.     if (status == SUCCESS && doTimeout && writeStatus==SUCCESS) {
  363.         writeStatus = Vm_CopyOut(sizeof(timeout), (Address) &timeout, 
  364.                             (Address) userTimeoutPtr);
  365.     }
  366.     if (writeStatus != SUCCESS) {
  367.         status = SYS_ARG_NOACCESS;
  368.     }
  369.     }
  370.     if (status == SUCCESS) {
  371.     return numReady;
  372.     } else if (status == GEN_ABORTED_BY_SIGNAL) {
  373.     Proc_GetCurrentProc()->unixProgress = PROC_PROGRESS_MIG_RESTART;
  374.     Mach_SetErrno(EINTR);
  375.     return -1;
  376.     } else if (status == FS_TIMEOUT) {
  377.     return 0;
  378.     } else {
  379.     Mach_SetErrno(EACCES);
  380.     return -1;
  381.     }
  382. }
  383.  
  384. /*ARGSUSED*/
  385. ReturnStatus
  386. Fs_Select(numStreams, timeoutPtr, inReadMaskPtr, outReadMaskPtr,
  387.     inWriteMaskPtr, outWriteMaskPtr, inExceptMaskPtr, outExceptMaskPtr,
  388.     numReadyPtr, doTimeoutPtr)
  389.     int        numStreams;    /* The length in bits of the read and write 
  390.                  * masks. */
  391.     Time    *timeoutPtr;    /* Timer value indicating timeout period or
  392.                  * NIL if no timeout. (in/out) */
  393.     int        *inReadMaskPtr;
  394.     int        *outReadMaskPtr;
  395.                 /* A bitmask indicating stream ID's to check
  396.                  * for readability. (in/out) */
  397.     int        *inWriteMaskPtr;
  398.     int        *outWriteMaskPtr;
  399.                 /* A bitmask indicating stream ID's to check
  400.                  * for writability. (in/out) */
  401.     int        *inExceptMaskPtr;
  402.     int        *outExceptMaskPtr;
  403.                 /* A bitmask indicating stream ID's to check
  404.                  * for exception conditions. (in/out) */
  405.     int        *numReadyPtr;    /* On return indicates the number of streams
  406.                  * ready for I/O. (out) */
  407.     int         *doTimeoutPtr;                 
  408.  
  409. {
  410.     Proc_ControlBlock    *procPtr;    /* This proc's control block */
  411.     Timer_QueueElement    wakeupElement;    /* Element for timeout. */
  412.     WakeupInfo        wakeupInfo;    /* Passed to timeout routine. */
  413.     Sync_RemoteWaiter    waiter;
  414.     int            row;        /* Index of row of inReadMasks,
  415.                      * inWriteMasks, inExceptMasks. */
  416.     register int    mask;        /* Selects bit within a row of
  417.                      * inReadMasks, inWriteMasks,
  418.                      * inExceptMasks. */
  419.     register int    inReadMask = 0;    /* Contents of a row of inReadMasks. */
  420.     register int    inWriteMask = 0;/* Contents of a row of inWriteMasks. */
  421.     int            inExceptMask = 0;/* Content of a row of inExceptMasks.*/
  422.     int            intsInMask;    /* # of integers in inReadMasks,
  423.                      * inWriteMasks and inExceptMasks. */
  424.     register int    bit;        /* Loop counter */
  425.     int            bitMax;        /* Loop terminating condition */
  426.     Boolean        poll;        /* If TRUE, don't wait if the first
  427.                      * check of streams finds that none
  428.                      * are ready now. */
  429.     int            s;        /* Temp copy of numStreams */
  430.     ReturnStatus    status = SUCCESS;
  431.  
  432.     /*
  433.      * If all the masks are NIL, then there aren't any streams to select.
  434.      * Set the numStreams to zero so we can see if we can return once the
  435.      * timeout argument is examined.
  436.      */
  437.     if ((inReadMaskPtr == (int *) NIL) &&
  438.         (inWriteMaskPtr == (int *) NIL) &&
  439.         (inExceptMaskPtr == (int *) NIL)) {
  440.     numStreams = 0;
  441.     }
  442.  
  443.     /*
  444.      * See if a timeout period was given. If so, set up a timer
  445.      * queue element to call TimeoutProc to wakeup the process.
  446.      * If the timeout is 0 or negative, just poll the streams to
  447.      * see if any are ready.
  448.      */
  449.  
  450.     if (timeoutPtr == (Time *) NIL) {
  451.     poll = FALSE;
  452.     *doTimeoutPtr = FALSE;
  453.     } else {
  454.     if ((timeoutPtr->seconds < 0) || 
  455.         ((timeoutPtr->seconds == 0) && (timeoutPtr->microseconds == 0))) {
  456.  
  457.         /*
  458.          * A zero or negative time was given. Assume the user wants to
  459.          * poll the streams.
  460.          */
  461.         *doTimeoutPtr = FALSE;
  462.         poll = TRUE;
  463.  
  464.     } else if (numStreams == 0) {
  465.  
  466.         /*
  467.          * Special case: nothing to select, but a valid timeout period
  468.          * was specified. Just wait for the timeout to expire.
  469.          */
  470.         if (Sync_WaitTime(*timeoutPtr)) {
  471.         return GEN_ABORTED_BY_SIGNAL;
  472.         } else {
  473.         return FS_TIMEOUT;
  474.         }
  475.     } else {
  476.         Timer_Ticks ticks;
  477.         Timer_Ticks currentTicks;
  478.         wakeupElement.routine = TimeoutProc;
  479.  
  480.         /*
  481.          * Convert the user's timeout value from a relative Time to a 
  482.          * an absolute time in the internal Timer_Ticks units.
  483.          *
  484.          * The value wakeupElement.time is used at the end of this
  485.          * routine to return the amount of time remaining in the timeout.
  486.          */
  487.         Timer_TimeToTicks(*timeoutPtr, &ticks);
  488.         Timer_GetCurrentTicks(¤tTicks);
  489.         Timer_AddTicks(currentTicks, ticks, &(wakeupElement.time));
  490.         poll = FALSE;
  491.         *doTimeoutPtr = TRUE;
  492.     }
  493.     }
  494.  
  495.     /*
  496.      * Nothing to select and no timeout specified so just return.
  497.      */
  498.     if (numStreams == 0) {
  499.     return status;
  500.     }
  501.  
  502.     intsInMask = (numStreams + (BITS_PER_ROW -1)) / BITS_PER_ROW;
  503.     procPtr = Proc_GetCurrentProc();
  504.  
  505.     /*
  506.      * If a timeout period was specified, set up a callback from the Timer 
  507.      * queue.
  508.      */
  509.     wakeupInfo.timeOut = FALSE;
  510.     if (*doTimeoutPtr) {
  511.     wakeupElement.clientData = (ClientData) &wakeupInfo;
  512.     wakeupInfo.procPtr = procPtr;
  513.     Timer_ScheduleRoutine(&wakeupElement, FALSE);
  514.     }
  515.  
  516.     waiter.hostID = rpc_SpriteID;
  517.  
  518.     while (TRUE) {
  519.  
  520.     /*
  521.      * Get the token to use for select waiting.  We must get the token
  522.      * before checking the timeout flag because there is a race 
  523.      * condition between the timeout wakeup and us getting the
  524.      * wait token.  If we checked timeOut before getting the token, it 
  525.      * is possible that a time out could come between checking the 
  526.      * flag and getting the wait token and we could miss the time out.
  527.      */
  528.     Sync_GetWaitToken(&waiter.pid, &waiter.waitToken);
  529.     if (wakeupInfo.timeOut) {
  530.         status = FS_TIMEOUT;
  531.         break;
  532.     }
  533.  
  534.     /*
  535.      * The read, write and except bit masks can be considered as
  536.      * arrays of bits, possibly more than 32 bits long. Each mask is
  537.      * represented as an array of ints such that row 0 corresponds to
  538.      * streams 0 through 31, row 1 corresponds to streams 32 though
  539.      * 63, etc. Within a row, the low-order bit corresponds to the
  540.      * smallest stream number.
  541.      */
  542.     s = numStreams + 1;
  543.     for (row = 0; row < intsInMask; row++) {
  544.         int    outReadMask = 0;
  545.         int    outWriteMask = 0;
  546.         int    outExceptMask = 0;
  547.  
  548.         if (inReadMaskPtr != (int *) NIL) {
  549.         inReadMask = inReadMaskPtr[row];
  550.         }
  551.         if (inWriteMaskPtr != (int *) NIL) {
  552.         inWriteMask = inWriteMaskPtr[row];
  553.         }
  554.         if (inExceptMaskPtr != (int *) NIL) {
  555.         inExceptMask = inExceptMaskPtr[row];
  556.         }
  557.         if (inReadMask != 0 || inWriteMask != 0 || inExceptMask != 0) {
  558.         /*
  559.          * At least one stream in this row was selected. Go through
  560.          * the masks to find the stream number and see if it's ready.
  561.          */
  562.         bitMax = (s > BITS_PER_ROW) ? BITS_PER_ROW : s;
  563.         for (mask = 1, bit = 0; bit < bitMax; mask <<= 1, bit++) {
  564.             /*
  565.              * Set up single bit masks that will be or'ed into
  566.              * the final result masks.
  567.              */
  568.             int readBit = inReadMask & mask;
  569.             int writeBit = inWriteMask & mask;
  570.             int exceptBit = inExceptMask & mask;
  571.  
  572.             if (readBit | writeBit | exceptBit) {
  573.             Fs_Stream    *streamPtr;
  574.  
  575.             if (Fs_GetStreamPtr(procPtr, row * BITS_PER_ROW + bit, 
  576.                             &streamPtr) != SUCCESS) {
  577.                 /*
  578.                  *  A stream was selected that probably 
  579.                  *  wasn't opened.
  580.                  */
  581.                 status = SYS_INVALID_ARG;
  582.                 goto deschedule;
  583.             } else {
  584.                 if (!(streamPtr->flags & FS_READ)) {
  585.                 readBit = 0;
  586.                 }
  587.                 if (!(streamPtr->flags & FS_WRITE)) {
  588.                 writeBit = 0;
  589.                 }
  590.                 /*
  591.                  * Call the I/O handle's select routine and
  592.                  * combine what's left in the single bit masks
  593.                  * into the final result masks.
  594.                  */
  595.  
  596.                 assert(((int) streamPtr & 3) == 0);
  597.                 assert(((int) streamPtr->ioHandlePtr & 3) == 0);
  598.  
  599.                 status = 
  600.         (*fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].select)
  601.                 (streamPtr->ioHandlePtr, &waiter,
  602.                  &readBit, &writeBit, &exceptBit);
  603.                 if (status != SUCCESS) {
  604.                 goto deschedule;
  605.                 }
  606.                 if (readBit | writeBit | exceptBit) {
  607.                 outReadMask |= readBit & mask;
  608.                 outWriteMask |= writeBit & mask;
  609.                 outExceptMask |= exceptBit & mask;
  610.                 ++*numReadyPtr;
  611.                 }
  612.             }
  613.             }
  614.         }
  615.         s -= BITS_PER_ROW;
  616.         }
  617.         if (outReadMaskPtr != (int *) NIL) {
  618.         outReadMaskPtr[row]   = outReadMask;
  619.         }
  620.         if (outWriteMaskPtr != (int *) NIL) {
  621.         outWriteMaskPtr[row]  = outWriteMask;
  622.         }
  623.         if (outExceptMaskPtr != (int *) NIL) {
  624.         outExceptMaskPtr[row] = outExceptMask;
  625.         }
  626.     }
  627.  
  628.     /*
  629.      * If at least 1 stream is ready or we're just polling, then quit.
  630.      * Otherwise, wait until we're notified that some stream became
  631.      * ready. When we wake up, start the loop again to find out which 
  632.      * stream(s) became ready.
  633.      */
  634.  
  635.     if (*numReadyPtr > 0 || poll) {
  636.         break;
  637.     } else {
  638.         if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  639.         status = GEN_ABORTED_BY_SIGNAL;
  640.         break;
  641.         }
  642.     }
  643.     }
  644.  
  645.     /*
  646.      * The wakeupInfo.timedOut flag is set by the routine called from 
  647.      * the timer queue. If the flag is not set, then remove the routine 
  648.      * from the queue.
  649.      */
  650. deschedule:
  651.     if (!wakeupInfo.timeOut && *doTimeoutPtr) {
  652.     Timer_DescheduleRoutine(&wakeupElement);
  653.     }
  654.  
  655.     /*
  656.      * Only copy out the masks if something is ready,
  657.      * or upon a timeout.  (Emacs, in particular, stupidly looks
  658.      * at the read masks after a timeout.).
  659.      */
  660.     if (status == SUCCESS || status == FS_TIMEOUT) {
  661.     if (status != SUCCESS) {
  662.         for (row=0 ; row<intsInMask ; row++) {
  663.         if (outReadMaskPtr != (int *) NIL) {
  664.             outReadMaskPtr[row] = 0;
  665.         }
  666.         if (outWriteMaskPtr != (int *) NIL) {
  667.             outWriteMaskPtr[row] = 0;
  668.         }
  669.         if (outExceptMaskPtr != (int *) NIL) {
  670.             outExceptMaskPtr[row] = 0;
  671.         }
  672.         }
  673.     }
  674.     if (status == SUCCESS && *doTimeoutPtr) {
  675.         /*
  676.          * A timeout period was given but some stream became ready
  677.          * before the period expired.  Return the amount of time that
  678.          * is remaining in the timeout value.
  679.          */
  680.  
  681.         Timer_Ticks temp;
  682.  
  683.         Timer_GetCurrentTicks(&temp);
  684.         Timer_SubtractTicks(wakeupElement.time, temp, &temp);
  685.         Timer_TicksToTime(temp, timeoutPtr);
  686.     }
  687.     }
  688.     return(status);
  689. }
  690.  
  691.  
  692. /*
  693.  *----------------------------------------------------------------------
  694.  *
  695.  * TimeoutProc --
  696.  *
  697.  *    This routine is called from the Timer queue if a select
  698.  *    call does not complete by a certain time.
  699.  *
  700.  * Results:
  701.  *    None.
  702.  *
  703.  * Side effects:
  704.  *    The timeOut field is set to TRUE. Other processes may be woken up.
  705.  *
  706.  *----------------------------------------------------------------------
  707.  */
  708.  
  709. /*ARGSUSED*/
  710. static void
  711. TimeoutProc(ticks, clientData)
  712.     Timer_Ticks    ticks;
  713.     ClientData    clientData;
  714. {
  715.     WakeupInfo    *wakeupInfoPtr = (WakeupInfo *) clientData;
  716.     wakeupInfoPtr->timeOut = TRUE;
  717.     Sync_ProcWakeup(wakeupInfoPtr->procPtr->processID,
  718.                     wakeupInfoPtr->procPtr->waitToken);
  719. }
  720.  
  721. static ReturnStatus
  722. readInMasks(numStreams, userReadMaskPtr, readMaskPtr,
  723.     userWriteMaskPtr, writeMaskPtr, userExceptMaskPtr, exceptMaskPtr)
  724.     int         numStreams;
  725.     int        *userReadMaskPtr;
  726.     int        *readMaskPtr;
  727.     int        *userWriteMaskPtr;
  728.     int        *writeMaskPtr;
  729.     int        *userExceptMaskPtr;
  730.     int        *exceptMaskPtr;
  731. {
  732.     int bytesInMask;
  733.     int status;
  734.  
  735.     if (numStreams == 0) {
  736.     return SUCCESS;
  737.     }
  738.     bytesInMask = ((numStreams+(BITS_PER_ROW -1))/BITS_PER_ROW)*sizeof(int);
  739.  
  740.     /*
  741.      * Copy in the masks from user's address space.
  742.      */
  743.     if (userReadMaskPtr != (int *) USER_NIL) {
  744.     status = Vm_CopyIn(bytesInMask, (Address) userReadMaskPtr, 
  745.                (Address) readMaskPtr);
  746.     if (status != SUCCESS) {
  747.         return(status);
  748.     }
  749.     }
  750.     if (userWriteMaskPtr != (int *) USER_NIL) {
  751.     status = Vm_CopyIn(bytesInMask, (Address) userWriteMaskPtr, 
  752.                 (Address) writeMaskPtr);
  753.     if (status != SUCCESS) {
  754.         return(status);
  755.     }
  756.     }
  757.     if (userExceptMaskPtr != (int *) USER_NIL) {
  758.     status = Vm_CopyIn(bytesInMask, (Address) userExceptMaskPtr, 
  759.                 (Address) exceptMaskPtr);
  760.     if (status != SUCCESS) {
  761.         return(status);
  762.     }
  763.     }
  764.     return SUCCESS;
  765. }
  766.  
  767. static ReturnStatus
  768. writeOutMasks(numStreams, userReadMaskPtr, readMaskPtr,
  769.     userWriteMaskPtr, writeMaskPtr, userExceptMaskPtr, exceptMaskPtr)
  770.     int         numStreams;
  771.     int        *userReadMaskPtr;
  772.     int        *readMaskPtr;
  773.     int        *userWriteMaskPtr;
  774.     int        *writeMaskPtr;
  775.     int        *userExceptMaskPtr;
  776.     int        *exceptMaskPtr;
  777. {
  778.     int bytesInMask;
  779.     int status;
  780.  
  781.     if (numStreams == 0) {
  782.     return SUCCESS;
  783.     }
  784.     bytesInMask = ((numStreams+(BITS_PER_ROW -1))/BITS_PER_ROW)*sizeof(int);
  785.     if (userReadMaskPtr != (int *)USER_NIL) {
  786.     status = Vm_CopyOut(bytesInMask, (Address) readMaskPtr,
  787.                           (Address) userReadMaskPtr);
  788.     if (status != SUCCESS) {
  789.         return(SYS_ARG_NOACCESS);
  790.     }
  791.     }
  792.     if (userWriteMaskPtr != (int *) USER_NIL) {
  793.     status = Vm_CopyOut(bytesInMask, (Address) writeMaskPtr,
  794.                           (Address) userWriteMaskPtr);
  795.     if (status != SUCCESS) {
  796.         return(SYS_ARG_NOACCESS);
  797.     }
  798.     }
  799.     if (userExceptMaskPtr != (int *) USER_NIL) {
  800.     status = Vm_CopyOut(bytesInMask, (Address) exceptMaskPtr,
  801.                           (Address) userExceptMaskPtr);
  802.     if (status != SUCCESS) {
  803.         return(SYS_ARG_NOACCESS);
  804.     }
  805.     }
  806.     return SUCCESS;
  807. }
  808.  
  809.